package utils

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os/exec"
	"strings"
	"time"
)

// WhoisResult WHOIS查询结果
type WhoisResult struct {
    Domain      string            `json:"domain"`
    RawData     string            `json:"raw_data"`
    ParsedData  map[string]string `json:"parsed_data,omitempty"`
    Registrar   string            `json:"registrar,omitempty"`
    CreatedDate string            `json:"created_date,omitempty"`
    UpdatedDate string            `json:"updated_date,omitempty"`
    ExpiryDate  string            `json:"expiry_date,omitempty"`
    NameServers []string          `json:"name_servers,omitempty"`
    Status      []string          `json:"status,omitempty"`
    StatusInfo  []*EPPStatus      `json:"status_info,omitempty"` // 详细状态信息
    DNSSEC      string            `json:"dnssec,omitempty"`
    QueryTime   time.Duration     `json:"query_time"`
    Source      string            `json:"source"` // "api" or "command"
}

// WhoisConfig WHOIS配置
type WhoisConfig struct {
	Primary  string `json:"primary"`  // API endpoint
	Fallback string `json:"fallback"` // "command" or another API
}

// WhoisClient WHOIS客户端
type WhoisClient struct {
	config     *WhoisConfig
	httpClient *http.Client
	timeout    time.Duration
}

// NewWhoisClient 创建WHOIS客户端
func NewWhoisClient(config *WhoisConfig) *WhoisClient {
	if config == nil {
		config = &WhoisConfig{
			Primary:  "https://whoisjsonapi.com/v1/",
			Fallback: "command",
		}
	}

	return &WhoisClient{
		config:  config,
		timeout: 10 * time.Second,
		httpClient: &http.Client{
			Timeout: 10 * time.Second,
		},
	}
}

// Query 查询WHOIS信息
func (w *WhoisClient) Query(ctx context.Context, domain string) (*WhoisResult, error) {
	if domain == "" {
		return nil, fmt.Errorf("domain cannot be empty")
	}

	// 清理域名
	domain = strings.TrimSpace(strings.ToLower(domain))
	domain = strings.TrimPrefix(domain, "http://")
	domain = strings.TrimPrefix(domain, "https://")
	domain = strings.TrimPrefix(domain, "www.")

	// 首先尝试API查询
	if w.config.Primary != "" && w.config.Primary != "command" {
		result, err := w.queryAPI(ctx, domain)
		if err == nil && result != nil {
			return result, nil
		}
	}

	// 失败则使用备用方案
	if w.config.Fallback == "command" {
		return w.queryCommand(ctx, domain)
	}

	return nil, fmt.Errorf("no available WHOIS source")
}

// queryAPI 通过API查询
func (w *WhoisClient) queryAPI(ctx context.Context, domain string) (*WhoisResult, error) {
	start := time.Now()

	url := w.config.Primary + domain
	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return nil, err
	}

	resp, err := w.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// 解析JSON响应
	var apiResponse map[string]interface{}
	if err := json.Unmarshal(body, &apiResponse); err != nil {
		// 如果不是JSON，可能是原始WHOIS数据
		return &WhoisResult{
			Domain:    domain,
			RawData:   string(body),
			QueryTime: time.Since(start),
			Source:    "api",
		}, nil
	}

	// 解析API响应
	result := &WhoisResult{
		Domain:     domain,
		RawData:    string(body),
		ParsedData: make(map[string]string),
		QueryTime:  time.Since(start),
		Source:     "api",
	}

	// 提取常见字段
	if registrar, ok := apiResponse["registrar"].(string); ok {
		result.Registrar = registrar
	}
	if created, ok := apiResponse["created_date"].(string); ok {
		result.CreatedDate = created
	}
	if updated, ok := apiResponse["updated_date"].(string); ok {
		result.UpdatedDate = updated
	}
	if expiry, ok := apiResponse["expiry_date"].(string); ok {
		result.ExpiryDate = expiry
	}

	// 提取名称服务器（统一小写并去重）
	if ns, ok := apiResponse["name_servers"].([]interface{}); ok {
		for _, n := range ns {
			if nsStr, ok := n.(string); ok {
				result.NameServers = append(result.NameServers, nsStr)
			}
		}
		result.NameServers = normalizeNameServers(result.NameServers)
	}

    // 提取状态（清洗为标准EPP状态）
    if status, ok := apiResponse["status"].([]interface{}); ok {
        for _, s := range status {
            if statusStr, ok := s.(string); ok {
                if cleaned := NormalizeEPPStatus(statusStr); cleaned != "" {
                    result.Status = append(result.Status, cleaned)
                }
            }
        }
    }

    // 提取 DNSSEC
    if dnssec, ok := apiResponse["dnssec"].(string); ok {
        result.DNSSEC = strings.ToLower(strings.TrimSpace(dnssec))
    }
    
    // 标准化和去重状态
    result.Status = normalizeStatuses(result.Status)
    // 获取状态详细信息
    result.StatusInfo = getStatusInfo(result.Status)

	return result, nil
}

// queryCommand 通过命令行查询
func (w *WhoisClient) queryCommand(ctx context.Context, domain string) (*WhoisResult, error) {
	start := time.Now()

	// 执行whois命令
	cmd := exec.CommandContext(ctx, "whois", domain)
	output, err := cmd.Output()
	if err != nil {
		// 某些域名可能没有WHOIS信息，这不算错误
		if exitErr, ok := err.(*exec.ExitError); ok {
			output = exitErr.Stderr
		} else {
			return nil, fmt.Errorf("whois command failed: %v", err)
		}
	}

	rawData := string(output)

	result := &WhoisResult{
		Domain:     domain,
		RawData:    rawData,
		ParsedData: make(map[string]string),
		QueryTime:  time.Since(start),
		Source:     "command",
	}

    // 解析WHOIS数据
    w.parseWhoisData(result)
    // 统一小写并去重名称服务器
    result.NameServers = normalizeNameServers(result.NameServers)
    // 去重和标准化状态
    result.Status = normalizeStatuses(result.Status)
    // 获取状态详细信息
    result.StatusInfo = getStatusInfo(result.Status)

	return result, nil
}

// parseWhoisData 解析WHOIS原始数据
func (w *WhoisClient) parseWhoisData(result *WhoisResult) {
    lines := strings.Split(result.RawData, "\n")

    for _, line := range lines {
        line = strings.TrimSpace(line)
        if line == "" || strings.HasPrefix(line, "%") || strings.HasPrefix(line, "#") {
            continue
        }

        // 分割键值对
        parts := strings.SplitN(line, ":", 2)
        if len(parts) != 2 {
            continue
        }

        key := strings.TrimSpace(parts[0])
        value := strings.TrimSpace(parts[1])

        // 标准化键名
        keyLower := strings.ToLower(key)

        // 存储到ParsedData
        result.ParsedData[key] = value

        // 提取特定字段
        switch {
        case (strings.Contains(keyLower, "registrar") || strings.Contains(keyLower, "sponsoring registrar")) && 
             !strings.Contains(keyLower, "url") && !strings.Contains(keyLower, "whois") && !strings.Contains(keyLower, "iana"):
            if result.Registrar == "" {
                // 处理可能的星号遮蔽
                if value != "" && !strings.Contains(value, "***") {
                    result.Registrar = value
                }
            }

        case strings.Contains(keyLower, "creation") || strings.Contains(keyLower, "created") || 
             strings.Contains(keyLower, "registration time") || strings.Contains(keyLower, "registered"):
            if result.CreatedDate == "" {
                result.CreatedDate = value
            }

        case strings.Contains(keyLower, "updated") || strings.Contains(keyLower, "modified") ||
             strings.Contains(keyLower, "last update"):
            if result.UpdatedDate == "" {
                result.UpdatedDate = value
            }

        case strings.Contains(keyLower, "expir") || strings.Contains(keyLower, "renewal") ||
             strings.Contains(keyLower, "expiration time"):
            if result.ExpiryDate == "" {
                result.ExpiryDate = value
            }

        case strings.Contains(keyLower, "name server") || strings.Contains(keyLower, "nserver"):
            result.NameServers = append(result.NameServers, value)

        case strings.HasPrefix(keyLower, "domain status") || keyLower == "status":
            if cleaned := NormalizeEPPStatus(value); cleaned != "" {
                result.Status = append(result.Status, cleaned)
            }

        case strings.Contains(keyLower, "dnssec"):
            if result.DNSSEC == "" {
                result.DNSSEC = strings.ToLower(value)
            }
        }
    }
}

// normalizeNameServers 将 NS 统一为小写并去重
func normalizeNameServers(ns []string) []string {
	seen := make(map[string]struct{}, len(ns))
	var out []string
	for _, n := range ns {
		n = strings.TrimSpace(strings.ToLower(n))
		if n == "" {
			continue
		}
		if _, ok := seen[n]; ok {
			continue
		}
		seen[n] = struct{}{}
		out = append(out, n)
	}
	return out
}

// normalizeStatuses 去重和标准化状态数组
func normalizeStatuses(statuses []string) []string {
	seen := make(map[string]struct{})
	var out []string
	
	for _, s := range statuses {
		normalized := NormalizeEPPStatus(s)
		if normalized == "" {
			continue
		}
		if _, ok := seen[normalized]; ok {
			continue
		}
		seen[normalized] = struct{}{}
		out = append(out, normalized)
	}
	
	// 按类型排序：ok优先，然后client状态，然后server状态，最后其他
	sortStatuses(out)
	return out
}

// getStatusInfo 获取状态详细信息
func getStatusInfo(statuses []string) []*EPPStatus {
	var infos []*EPPStatus
	for _, status := range statuses {
		if info := GetEPPStatusInfo(status); info != nil {
			infos = append(infos, info)
		}
	}
	return infos
}

// sortStatuses 对状态进行排序
func sortStatuses(statuses []string) {
	// 定义优先级
	priority := func(s string) int {
		if s == "ok" {
			return 0
		}
		if strings.HasPrefix(s, "client") {
			return 1
		}
		if strings.HasPrefix(s, "server") {
			return 2
		}
		if strings.HasPrefix(s, "pending") {
			return 3
		}
		return 4
	}
	
	// 排序
	for i := 0; i < len(statuses); i++ {
		for j := i + 1; j < len(statuses); j++ {
			if priority(statuses[i]) > priority(statuses[j]) ||
				(priority(statuses[i]) == priority(statuses[j]) && statuses[i] > statuses[j]) {
				statuses[i], statuses[j] = statuses[j], statuses[i]
			}
		}
	}
}

// BatchQuery 批量查询
func (w *WhoisClient) BatchQuery(ctx context.Context, domains []string) ([]*WhoisResult, error) {
	results := make([]*WhoisResult, len(domains))

	for i, domain := range domains {
		result, err := w.Query(ctx, domain)
		if err != nil {
			// 记录错误但继续
			results[i] = &WhoisResult{
				Domain:  domain,
				RawData: fmt.Sprintf("Error: %v", err),
				Source:  "error",
			}
		} else {
			results[i] = result
		}

		// 避免过于频繁的查询
		if i < len(domains)-1 {
			time.Sleep(500 * time.Millisecond)
		}
	}

	return results, nil
}
